/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2002 Copyright (C)
 *
 *  File: nim_zl10039.c
 *
 *  Description: This file contains ZL10039 basic function in LLD.
 *
 *  History:
 *      Date        Author      Version  Comment
 *      ====        ======      =======  =======
 *  1.  2005.7      Hao Huang     0.1.000  Initial
 *
 ****************************************************************************/

#include <sys_config.h>


#include <retcode.h>
#include <types.h>

#include <bus/i2c/i2c.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <osal/osal_timer.h>
#include "nim_zl10039.h"

INT32 nim_zl10039_control_BW(struct QPSK_TUNER_CONFIG_EXT* stZL10039_ptr, UINT16 sym);
struct QPSK_TUNER_CONFIG_EXT * stZL10039_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stZL10039_tuner_cnt = 0;
/*****************************************************************************
* INT32 nim_zl10039_read(UINT8 reg,UINT8* buff,UINT8 len)
*
* Tuner read register from zl10039
*
* Arguments:
*  Parameter1: UINT8 reg		: Register offset of MAX2118
*  Parameter2: UINT8* buff		: Read data buffer
*  Parameter3: UINT8 len		: Read length
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_zl10039_read(UINT32 i2c_type_id, UINT8 base_addr, UINT8 reg,UINT8* buff,UINT8 len)
{
	return i2c_write_read(i2c_type_id, base_addr, buff, 1 , len);
}

/*****************************************************************************
* INT32 nim_zl10039_write(UINT8 reg,UINT8* buff,UINT8 len)
*
* Tuner write register from zl10039
*
* Arguments:
*  Parameter1: UINT8 reg		: Register offset of MAX2118
*  Parameter2: UINT8* buff		: write data buffer
*  Parameter3: UINT8 len		: write length
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_zl10039_write(UINT32 i2c_type_id, UINT8 base_addr, UINT8 reg,UINT8* buff,UINT8 len)
{
	UINT8  i, buffer[18];
	INT32  result;

	if (len > 16)
	{
	    return ERR_FAILUE;
	}
	buffer[0] = reg;
	for (i = 0; i < len; i++)
	{
	    buffer[i + 1] = buff[i];
	}
	return i2c_write(i2c_type_id, base_addr, buffer, len+1);
}


/*****************************************************************************
* INT32 nim_zl10039_init(UINT32 para, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
*
* Tuner ZL10039 Initialization
*
* Arguments:
*  Parameter1: UINT32 para		: Input Parameter
*  Parameter2: struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config		: pointer for Tuner configuration structure
*
* Return Value: INT32			: Result
*****************************************************************************/
static UINT8 init_act[2] = {0, 0};

INT32 nim_zl10039_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	INT32	result = 200;
	UINT8 ucTemp;
	UINT8 ucDiv[2];
	UINT8 ZL1003Z_R2_C;
	UINT8 ZL1003Z_R7;
	struct QPSK_TUNER_CONFIG_EXT * stZL10039_ptr = NULL;
	ZL10039_DEBUG("enter nim_zl10039_init \n");


	/* check Tuner Configuration structure is available or not */
	if (ptrTuner_Config == NULL||stZL10039_tuner_cnt>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stZL10039_ptr = (struct QPSK_TUNER_CONFIG_EXT*)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!stZL10039_ptr)
		return ERR_FAILUE;
	stZL10039_dev_id[stZL10039_tuner_cnt] = stZL10039_ptr;
	MEMCPY(stZL10039_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
/*	soc_printf("%s: sizeof QPSK_TUNER_CONFIG_EXT = %d\n", __FUNCTION__, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	soc_printf("Base Address: 0x%x\n",stZL10039_Config.cTuner_Base_Addr);
	soc_printf("Tuner Crystal: %dKHz\n",stZL10039_Config.wTuner_Crystal);
	soc_printf("Output Mode: %d (1 -- Signle End; 0 -- Differential)\n",stZL10039_Config.cTuner_Out_S_D_Sel);
*/
	*tuner_id = stZL10039_tuner_cnt;
	stZL10039_tuner_cnt++;
/*	
	ucTemp = 0x40 ;
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x0F, &ucTemp, 0x01);
	ZL10039_DEBUG( " I2c write is 0x%x\n", result );
	osal_delay(10000);

	ucTemp = 0x00;
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x0F, &ucTemp, 0x01);
	ZL10039_DEBUG( " I2c write 1 is 0x%x\n", result );

	// Need Delay here about 1ms - 4ms to allow for power up  
	osal_delay(10000);

	ZL1003Z_R2_C = 0x02;//0x02;
	ucTemp = (ZL1003Z_R2_C << 4) | 0x0A;
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x02, &ucTemp, 0x01);
	//ZL10039_DEBUG( " I2c write 2 is 0x%x\n", result );


	if (stZL10039_ptr->wTuner_Crystal == 10111)
		ucTemp = 0x0a;//tiancheng
	else if (stZL10039_ptr->wTuner_Crystal == 10000)
		ucTemp = 0x0a;//tiandixing
	else if (stZL10039_ptr->wTuner_Crystal == 4000)
		ucTemp = 0x04;//tongda
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x06, &ucTemp, 0x01);

	ucTemp = 0xee;
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x04, &ucTemp, 0x01);

	ZL1003Z_R7 = 0x06;
	ucTemp = (ZL1003Z_R7 << 3);
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x07, &ucTemp, 0x01);

	ucDiv[0] = 0x05;
	ucDiv[1] = 0xFD;
	result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x00, ucDiv, 0x02);

 	result = nim_zl10039_read(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x08, &ucTemp, 0x01); //* for delay 
*/
	result = SUCCESS;

	return result;
}


INT32 nim_zl10039_control(UINT32 tuner_id, UINT32 freq ,UINT32 sym )
{
    	unsigned int divider =0;
	UINT8   data[2];
	struct QPSK_TUNER_CONFIG_EXT * stZL10039_ptr = NULL;
	
	if (tuner_id>=stZL10039_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stZL10039_ptr = stZL10039_dev_id[tuner_id];
    
#ifdef ZL10039_INIT_MULTI_TIME_SUPPORT	//add by kevin tian
	init_act[tuner_id] = 0;
#endif

	if (init_act[tuner_id] == 0) //do the init here.
	{
		INT32	result = 200;
		UINT8 ucTemp;
		UINT8 ucDiv[2];
		UINT8 ZL1003Z_R2_C;
		UINT8 ZL1003Z_R7;

		ucTemp = 0x40 ;
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x0F, &ucTemp, 0x01);
		ZL10039_DEBUG( " I2c write is 0x%x\n", result );
		osal_delay(10000);

		ucTemp = 0x00;
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x0F, &ucTemp, 0x01);
		ZL10039_DEBUG( " I2c write 1 is 0x%x\n", result );

		// Need Delay here about 1ms - 4ms to allow for power up  
		osal_delay(10000);

		ZL1003Z_R2_C = 0x02;//0x02;
		ucTemp = (ZL1003Z_R2_C << 4) | 0x0A;
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x02, &ucTemp, 0x01);
		//ZL10039_DEBUG( " I2c write 2 is 0x%x\n", result );


		if (stZL10039_ptr->wTuner_Crystal == 10111)
			ucTemp = 0x0a;//tiancheng
		else if (stZL10039_ptr->wTuner_Crystal == 10000)
			ucTemp = 0x0a;//tiandixing
		else if (stZL10039_ptr->wTuner_Crystal == 4000)
			ucTemp = 0x04;//tongda
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x06, &ucTemp, 0x01);

		ucTemp = 0xee;
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x04, &ucTemp, 0x01);

		ZL1003Z_R7 = 0x06;
		ucTemp = (ZL1003Z_R7 << 3);
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x07, &ucTemp, 0x01);

		ucDiv[0] = 0x05;
		ucDiv[1] = 0xFD;
		result = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x00, ucDiv, 0x02);

	 	result = nim_zl10039_read(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x08, &ucTemp, 0x01); /* for delay */

		init_act[tuner_id] = 1;	
	}
	
    	if (freq < 950)
		freq = 950;
    	else if (freq > 2160)
		freq = 2160;

	
	divider = (freq * 10000) / stZL10039_ptr->wTuner_Crystal;

    	data[0] = (unsigned char)((divider >> 8) & 0x7F);
    	data[1] = (unsigned char)divider;

	nim_zl10039_control_BW(stZL10039_ptr, sym );

    	return nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x00, data, 2);
}



INT32 nim_zl10039_control_BW(struct QPSK_TUNER_CONFIG_EXT* stZL10039_ptr, UINT16 sym )
{
	UINT16 ucBWMHz;
	UINT32 ucBF;
	UINT8  ucBuffer;
    BOOL  bRet = TRUE;

	if( 0 == sym )
		sym = 45000;

	sym = sym + ZL_BW_ADD;
	ucBWMHz = sym / 1000 + 1;

	/* limit absolute bandwidth to 8 to 40 MHz */
    if (ZL10039_BW_MIN > ucBWMHz)
		ucBWMHz = ZL10039_BW_MIN;
    if (ZL10039_BW_MAX < ucBWMHz)
		ucBWMHz = ZL10039_BW_MAX;
	ZL10039_DEBUG(" ucBWMHz is %d\n",ucBWMHz );
	ucBF = 50280;
	ucBF = ucBWMHz * ucBF;
	ucBF = (ucBF + 5000)/10000;
	ucBF = ucBF  - 1;

	//ucBF = 200;
    	ZL10039_DEBUG(" ucBF is %d\n",ucBF );

	if(stZL10039_ptr->wTuner_Crystal == 10111)
		ucBuffer = 0x0a;//tiancheng
	else if(stZL10039_ptr->wTuner_Crystal == 10000)
		ucBuffer = 0x0a;//tiandixing
	else if( stZL10039_ptr->wTuner_Crystal == 4000 )
		ucBuffer = 0x04;//tongda
	else if(stZL10039_ptr->wTuner_Crystal == 13500 )
		ucBuffer = 0x0e;		
	bRet = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x06, &ucBuffer, 0x01);

	bRet = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x05, (UINT8 *)&ucBF, 0x01);

	if(stZL10039_ptr->wTuner_Crystal == 10111)
		ucBuffer = 0x2a;//tiancheng
	else if(stZL10039_ptr->wTuner_Crystal == 10000)
		ucBuffer = 0x2a;//tiandixing
	else if(stZL10039_ptr->wTuner_Crystal == 4000 )
		ucBuffer = 0x24;//tongda
	else if(stZL10039_ptr->wTuner_Crystal == 13500 )
		ucBuffer = 0x2e;
	bRet = nim_zl10039_write(stZL10039_ptr->i2c_type_id, stZL10039_ptr->cTuner_Base_Addr, 0x06, (UINT8 *)&ucBuffer, 0x01);

    return bRet;
}

INT32 nim_zl10039_status(UINT32 tuner_id, UINT8 *lock)
{
	long result;
    	unsigned char data;
	struct QPSK_TUNER_CONFIG_EXT * stZL10039_ptr = NULL;
	if (tuner_id>=stZL10039_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	stZL10039_ptr = stZL10039_dev_id[tuner_id];
    	result = nim_zl10039_read(stZL10039_ptr->i2c_type_id,  stZL10039_ptr->cTuner_Base_Addr, 0x00, &data, 1);
	ZL10039_DEBUG(" nim_zl10039_status data is 0x%x\n", data );
    	*lock = (data & 0x80)>>7 ;

    	return result;
}

